This week's focus was on programming a microcontroller. The individual assignment was to read a microcontroller datasheet and program a board to do something, using at least two different development workflows. The group assignment was to compare the performance and development workflows for different microcontroller architectures.
Our full group documentation, where we compare different microcontrollers and their development environments, can be found on our group assignment page.
For our group assignment, we compared two main programming approaches: MicroPython and the Arduino (C/C++) framework.
In short, we found a clear trade-off: MicroPython is superior for rapid testing and real-time data, while Arduino is the better choice when final performance and speed are the priority.
For my individual assignment, I will be programming the XIAO ESP32-C3 board, which features the ESP32-C3 microcontroller from Espressif. I will first simulate the task on Wokwi to see how it works, and then I will implement it on the actual hardware using two different workflows: the Arduino IDE and python on thonny.
The first step was to understand the board and its microcontroller. The XIAO ESP32-C3 uses the ESP32-C3FN4 chip from Espressif. This is a 32-bit RISC-V single-core processor, which is a significant step up from the 8-bit AVR chips.
| Feature | Specification |
|---|---|
| CPU | RISC-V 32-bit single-core |
| Max Frequency | 160 MHz |
| On-Chip Memory | 400 KB SRAM + 4 MB Flash |
| Wireless | 2.4GHz Wi-Fi (802.11 b/g/n) and Bluetooth 5 (LE) |
| GPIOs | Up to 22 (11 available on the XIAO) |
| Interfaces | I2C, I2S, SPI, UART, ADC |
| Operating Voltage | 3.3V |
The most critical information for programming is the pinout. I needed to map the physical pins on the tiny XIAO board to their GPIO (General Purpose Input/Output) numbers and their names in the Arduino IDE.
| XIAO Pin | Arduino Name | GPIO Number | Functions |
|---|---|---|---|
| D0 | `D0` / `A0` | GPIO2 | ADC1_CH2, UART1_TXD |
| D1 | `D1` / `A1` | GPIO3 | ADC1_CH3 |
| D2 | `D2` / `A2` | GPIO4 | ADC1_CH4, I2C SDA |
| D3 | `D3` / `A3` | GPIO5 | ADC1_CH5, I2C SCL |
| D4 | `D4` | GPIO6 | SPI_CLK |
| D5 | `D5` | GPIO7 | SPI_MISO |
| D6 | `D6` | GPIO21 | UART0_TX (Serial) |
| D7 | `D7` | GPIO20 | UART0_RX (Serial) |
| D8 | `D8` | GPIO8 | SPI_MOSI, BOOT Button |
| D9 | `D9` | GPIO9 | SPI_CS |
| D10 | `D10` | GPIO10 | SPI_HD |
| LED | (No Arduino Name) | GPIO8 | Onboard User LED (Blue) |
Before working on the actual hardware, I simulated my program on Wokwi, an online simulator for microcontrollers.
I started off simple by first just connecting a push button with an Led and trying to simulate that. I connected the led cathode to ground and the anode to a resistor and pin 9. The button to ground and pin 8. Here I encountered an error because in the code I had actually used pin 9 for the button and pin 8 for the led. However, there were a few errors first this was not the xiao c3 and moreover the pin 8 was occupied by the board for on board LED which caused nothing to happen once the button was pressed.
First I changed the board to the xiao ESP32-C3 then wrote the code again and did the wiring. However, I didn't assign D to the pin numbers becasue of which the code didn't work and I spent quite a lot of time changing the circuit and then finally when i added the D to make it D2 and D3 it finally worked. After fixing the pin numbers I was able to get the led to turn off when the button was pressed. Here is the code I used for the simulation:
const int buttonPin = D2; // pushbutton pin
const int ledPin = D3; // LED pin
int buttonState = 0;
void setup() {
Serial.begin(115200);
// enable internal pull-up resistor
pinMode(buttonPin, INPUT_PULLUP);
// LED output
pinMode(ledPin, OUTPUT);
}
void loop() {
// read the state of the pushbutton (LOW = pressed)
buttonState = digitalRead(buttonPin);
Serial.println(buttonState);
// button pressed?
if (buttonState == HIGH) { // active LOW
digitalWrite(ledPin, HIGH); // turn LED on
} else {
digitalWrite(ledPin, LOW); // turn LED off
}
delay(1000);
}
Here is what diagram looked like:
After successfully simulating the program on Wokwi, I moved on to implementing it on the actual XIAO ESP32-C3 hardware on breadboard using the Arduino IDE.I first downloaded the Arduino IDE from the offical website and then downloaded the esp32 board support package from the board manager which took some time to install. The wiring was the same as in the simulation: the button connected to pin D2 and ground, and the LED connected to pin D3 with a current-limiting resistor to ground. I used male to male jumper cables to connect everything with the GND to the breadboard ground rails and the rest as before.
This is what the circuit looked like:
The code is the same as above and I uploaded it to the board and it worked perfectly. When I pressed the button, the LED turned off, and when I released it, the LED turned back on. I also monitored the serial output to see the button state being printed every second.
Here is a video of the setup in action:
Here is a picture of the serial monitor showing the button state:
As you can see the button state is printed as 1 when the button is not pressed and 0 when it is pressed, which confirms that the program is working as expected.
To satisfy the requirement of using two different workflows, I decided to recreate the exact same physical circuit using MicroPython. For this, I used Thonny, which is an excellent beginner-friendly Python IDE designed specifically for microcontrollers.
Unlike Arduino, which compiles the C++ code and flashes it directly to the board, MicroPython requires an interpreter to be installed on the microcontroller first.
Here is the flashing process in action:
A major difference I discovered between the Arduino workflow and MicroPython is how pins are addressed. In Arduino, I used the aliases D2 and D3. However, in MicroPython, you must address the pins by their actual hardware GPIO numbers. Looking back at my datasheet table in Step 1, I saw that D2 maps to GPIO4 and D3 maps to GPIO5.
Here is the MicroPython code to replicate the button and LED logic:
from machine import Pin
import time
# Initialize pins using actual GPIO numbers
# D2 is GPIO4 (Button), D3 is GPIO5 (LED)
button = Pin(4, Pin.IN, Pin.PULL_UP)
led = Pin(5, Pin.OUT)
print("Starting MicroPython Button Test...")
while True:
# Read button state (1 = unpressed, 0 = pressed due to PULL_UP)
button_state = button.value()
print("Button State:", button_state)
if button_state == 1:
led.value(1) # Turn LED on when not pressed
else:
led.value(0) # Turn LED off when pressed
time.sleep(1) # Delay to match the Arduino sketch
One of the massive advantages of MicroPython is the REPL (Read-Eval-Print Loop). As soon as I clicked the "Run" button in Thonny, the code executed immediately without needing to wait for a compiler. I could see the print() statements updating live in the Thonny shell at the bottom of the screen.
The physical hardware reacted exactly as it did in the Arduino test, successfully proving the second workflow!
In conclusion, this week was a fantastic learning experience. I got to explore the differences between two major programming workflows for microcontrollers and successfully implemented the same functionality using both Arduino and MicroPython. The interactive nature of MicroPython was particularly impressive, allowing for rapid testing and debugging without the need for a compile-upload cycle.
← Back to Main Page